package com.client.rule;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.client.rule.decision.DecisionEditorDialogBox;
import com.client.rule.decision.DecisionEditorDialogBoxFactory;
import com.client.rule.triple.TripleParser;
import com.client.rule.triple.UiComplexTriple;
import com.client.rule.triple.UiSimpleTriple;
import com.client.rule.triple.UiTriple;
import com.client.service.rule.DecisionMakerService;
import com.client.service.rule.DecisionMakerServiceAsync;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.XMLParser;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.Node;
import com.shared.rule.TypeDataRule;
import com.shared.rule.TypeDecision;

public class PanelRuleComposition extends Composite{

	private Tree ruleCompositionTree= new Tree();
	private Button boutonNew= new Button();
	private Button boutonLoad = new Button();
	private Button boutonSave = new Button();
	private Button boutonAjouterCondition = new Button();
	private Button boutonAjouterDecision = new Button();
	private Button boutonEnleverItem = new Button();
	private ListBox listDm = new ListBox();
	private final DecisionMakerServiceAsync decisionService = GWT.create(DecisionMakerService.class);
	
	VerticalPanel dataPanel = new VerticalPanel();
	Map<String,TypeDataRule> availableData = new HashMap<String, TypeDataRule>();
	Tree dataTree = new Tree();
	private String cible = "";
	
	private NewDialogBox newDialogBox = new NewDialogBox();
	
	private ListBox listDecision = new ListBox();
	
	private Button createComplementButton = new Button();
	
	private HTML helpLabel = new HTML();	;
	private static String aideConditionHtml = "<b> Aide :</b> Entrez une condition au clavier en utilisant les données disponibles visibles à droite. Vérifier que le type et les opérateurs (=,<>,> ou <) correspondent.";
	private static String aideNomHtml = "<b> Aide :</b> Entrez le nom de la règle. Ce nom sera utilisé lors de la sauvegarde et lors de l'utilisation de cette règle.";
	
	
	public PanelRuleComposition() {
		boutonAjouterCondition.setEnabled(false);
		boutonAjouterDecision.setEnabled(false);
		boutonEnleverItem.setEnabled(false);
		
		
		initWidget(createPanelRuleComposition());
		
		newDialogBox.addCloseHandler(new CloseHandler<PopupPanel>() {
			
			public void onClose(CloseEvent<PopupPanel> event) {
				cible = newDialogBox.getSelectedCible();	
				createNew();
			}
		});
		
		
		
		decisionService.getAvailableDM(new AsyncCallback<String[]>() {			
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage()) ;				
			}			
			public void onSuccess(String[] result) {
				for (int i=0; i<result.length;i++){
					listDm.addItem(result[i]) ;
				}				
			}			
		});
		
		boutonNew.addClickHandler(new ClickHandler() {
			
			public void onClick(ClickEvent event) {
				newDialogBox.center();	
				newDialogBox.show();
				
			}
		});
		
		boutonLoad.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {
				
				decisionService.getDMasString(listDm.getItemText(listDm.getSelectedIndex()), new AsyncCallback<String>() {			
					public void onSuccess(String result) {
						
						Document xmlDocument = XMLParser.parse(result);		
						
						generateFromXML(xmlDocument.getLastChild(),listDm.getItemText(listDm.getSelectedIndex()));
						
								
					}			
					public void onFailure(Throwable caught) {
						Window.alert(caught.getMessage()) ;		
						
					}
				});		
			}
		});
		
		boutonAjouterCondition.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {					
				if(isSelectedComposite() || isSelectedRoot()){	
					
						hideWidgets();
						ruleCompositionTree.getSelectedItem().addItem(new UiRuleComposite());
					
				}
			}
		});
		
		
		boutonEnleverItem.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {
				ruleCompositionTree.getSelectedItem().getParentItem().removeItem(ruleCompositionTree.getSelectedItem());					
			}
		});
		
		boutonAjouterDecision.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {
				
				if(isSelectedComposite() || isSelectedRoot()){
						hideWidgets();
						final TypeDecision typeSelected = TypeDecision.getTypeDecision(listDecision.getItemText(listDecision.getSelectedIndex()));
						final DecisionEditorDialogBox dialogBox = DecisionEditorDialogBoxFactory.createDialogBox(typeSelected);
						
						dialogBox.addCloseHandler(new CloseHandler<PopupPanel>() {							
							public void onClose(CloseEvent<PopupPanel> event) {								
								if(dialogBox.isChecked()){
									ruleCompositionTree.getSelectedItem().addItem(new UiDecision(dialogBox.getLabel(),typeSelected,dialogBox.getDecisionData()));
								}
							}
						});	
						dialogBox.center();					
				}
			}
		});
		
			
		
		ruleCompositionTree.addSelectionHandler(new SelectionHandler<TreeItem>() {
			
			
			public void onSelection(SelectionEvent<TreeItem> event) {
					hideWidgets();	
					boutonEnleverItem.setEnabled(true);
					boutonAjouterCondition.setEnabled(true);
					boutonAjouterDecision.setEnabled(true);
					createComplementButton.setEnabled(true);
					listDecision.setEnabled(true);
					if(isSelectedRoot()){
						getRoot().showWidget();	
						helpLabel.setHTML(aideNomHtml);
						helpLabel.setVisible(true);
						createComplementButton.setEnabled(false);
						dataPanel.setVisible(false);						
					}
					if(isSelectedComposite()){	
						helpLabel.setHTML(aideConditionHtml);
						helpLabel.setVisible(true);
						((UiRuleComposite) ruleCompositionTree.getSelectedItem()).showWidget();	
						dataPanel.setVisible(true);
						
					}
					if(isSelectedDecision()){
						boutonAjouterDecision.setEnabled(false);
						boutonAjouterCondition.setEnabled(false);
						createComplementButton.setEnabled(false);
						dataPanel.setVisible(false);
						listDecision.setEnabled(false);
					}
				
			}
		});
		
						
		
		
		createComplementButton.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {
				if(isSelectedComposite()){	
					hideWidgets();
					UiRuleComposite newRule = ((UiRuleComposite) ruleCompositionTree.getSelectedItem()).getComplement();
					//newRule.setText();
					ruleCompositionTree.getSelectedItem().getParentItem().addItem(newRule);					
				}
				
			}
		});
		
		boutonSave.addClickHandler(new ClickHandler() {			
			public void onClick(ClickEvent event) {
				hideWidgets();
				
				try{
				String content = toXml();				
					decisionService.saveDM(getRoot().getText(), toXml(), new AsyncCallback<String>() {
						
						public void onSuccess(String result) {
							Window.confirm("Sauvegarde effectuée");
							
						}					
						public void onFailure(Throwable caught) {
							Window.alert(caught.getMessage());						
						}
					});	
				
				}catch (IllegalArgumentException e) {
					Window.alert(e.getMessage());
				}
			}
		});
		listDecision.addItem(TypeDecision.MESSAGE.toString());
		listDecision.addItem(TypeDecision.PRODUIT.toString());		
	}
	
	
	public void hideWidgets(){
		getRoot().setText();
		for(int i=0;i<getRoot().getChildCount();i++){
			hideWidgets((UiRule) getRoot().getChild(i));
		}
	}
	
	public void hideWidgets(UiRule uiRule){
		if(uiRule.isComposite()){
			((UiRuleComposite) uiRule).setText();
			for(int i=0;i<((UiRuleComposite) uiRule).getChildCount();i++){
				hideWidgets((UiRule) uiRule.getChild(i));
			}
		}
	}
	
	public RootItem getRoot(){
		return (RootItem) ruleCompositionTree.getItem(0);
	}
	
	
	public boolean isSelectedRoot(){
		return ruleCompositionTree.getSelectedItem().equals(ruleCompositionTree.getItem(0));
	}
	
	public boolean isSelectedComposite(){
		if(isSelectedRoot()) return false;
		return ((UiRule) ruleCompositionTree.getSelectedItem()).isComposite();
	}
	
	public boolean isSelectedDecision(){
		if(isSelectedRoot()) return false;
		if(isSelectedComposite()) return false;
		return true;
	}
	
	public boolean hasSelectedDecision(){
		if(!isSelectedComposite()) return false;
		return ((UiRuleComposite) ruleCompositionTree.getSelectedItem()).hasDecision();
	}
	
	public VerticalPanel createPanelRuleComposition(){
		final VerticalPanel panelRuleComposition = new VerticalPanel();
		panelRuleComposition.setSpacing(5);
		//Load layout
		HorizontalPanel loadPanel = new HorizontalPanel();		
		loadPanel.setSpacing(10);
		
		panelRuleComposition.add(loadPanel);
		boutonNew.setText("Nouveau");
		loadPanel.add(boutonNew);
		Label labelForListDM = new Label("Disponible :");
		loadPanel.add(labelForListDM);
		
		
		loadPanel.add(listDm);
		
		boutonLoad.setText("Charger");
		boutonSave.setText("Sauver");
		
		
		loadPanel.add(boutonLoad);
		loadPanel.add(boutonSave);
		
		panelRuleComposition.add(helpLabel);
		helpLabel.setVisible(false);
		//View	
		HorizontalPanel viewEditor = new HorizontalPanel();
		viewEditor.setSpacing(5);
		Label labelEdit = new Label("Edition :");		
		labelEdit.setStyleName("titre") ;
		panelRuleComposition.add(labelEdit);
		
		VerticalPanel viewDmPanel = new VerticalPanel();
				
		ruleCompositionTree.setWidth("400px");
		ruleCompositionTree.setHeight("350px");
		DecoratorPanel decoRuleTree = new DecoratorPanel();
		decoRuleTree.add(ruleCompositionTree);
		viewDmPanel.add(decoRuleTree);
		HorizontalPanel panelBoutton1= new HorizontalPanel();
		HorizontalPanel panelBoutton2= new HorizontalPanel();
		panelBoutton1.setSpacing(5);
		panelBoutton2.setSpacing(5);
		boutonAjouterCondition.setText("+ Condition");
		boutonAjouterDecision.setText("+ Decision");
		boutonEnleverItem.setText("Enlever");		
		createComplementButton.setText("Complement");
		panelBoutton1.add(boutonAjouterCondition);
		panelBoutton2.add(listDecision);
		panelBoutton2.add(boutonAjouterDecision);
		panelBoutton1.add(boutonEnleverItem);
		panelBoutton2.add(createComplementButton);
		
		viewDmPanel.add(panelBoutton1);	
		viewDmPanel.add(panelBoutton2);
		viewEditor.add(viewDmPanel);
		
		
		dataPanel.setSpacing(5);
		//dataPanel.add(new Label("Donnes disponible : "));
		dataPanel.add(dataTree);
		dataPanel.setVisible(false);
		viewEditor.add(dataPanel);
		
		panelRuleComposition.add(viewEditor);	
				
		
		
		return panelRuleComposition ;
	}
	
	public String toXml() throws IllegalArgumentException{
		
		String	xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
			
		xml=xml+"<DecisionMaker label=\""+ruleCompositionTree.getItem(0).getText()+"\" cible=\"Assure\">";
		xml=xml+"<DecisionMakerData>";		
		Map<String,String> usedData = getUsedDataXml();
		for(String key : usedData.keySet()) xml=xml+usedData.get(key);
		xml=xml+"</DecisionMakerData>";
		xml=xml+"<BaseComponent type=\"BaseComponent\">";		
		for(int i=0;i<ruleCompositionTree.getItem(0).getChildCount();i++){
			xml=xml+((UiRule) ruleCompositionTree.getItem(0).getChild(i)).toXml(availableData);
		}
		xml=xml+"</BaseComponent>";
		xml=xml+"</DecisionMaker>";
		return xml;
	}
	
	public Map<String,String> getUsedDataXml(){
		Map<String,String> usedData = new HashMap<String, String>();		
		
		for(int i=0;i<ruleCompositionTree.getItem(0).getChildCount();i++){
			
			((UiRule) ruleCompositionTree.getItem(0).getChild(i)).getUsedDataXml(usedData,availableData);
		}
		return usedData;
	}
	 
	public void createNew(){
		ruleCompositionTree.clear();
		dataTree.clear();
		RootItem root = new RootItem("Nom du Systeme");
		decisionService.getData(cible,new AsyncCallback<Map<String,TypeDataRule>>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());				
			}
			public void onSuccess(Map<String, TypeDataRule> result) {	
				availableData = result;	
				for(String key : availableData.keySet()) dataTree.addItem(key+" type : " + availableData.get(key).toString());
			}
		});
		ruleCompositionTree.addItem(root);
	}
	
	public void generateFromXML(Node xmlNode,String name){
		ruleCompositionTree.clear();	
		dataTree.clear();
		RootItem root = new RootItem(name);
		
		
		
		ruleCompositionTree.setTitle(name);
		Element ruleElement = (Element) xmlNode;		
		cible = ruleElement.getAttribute("cible");
		decisionService.getData(cible,new AsyncCallback<Map<String,TypeDataRule>>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());				
			}
			public void onSuccess(Map<String, TypeDataRule> result) {	
				availableData = result;	
				for(String key : availableData.keySet()) dataTree.addItem(key+" type : " + availableData.get(key).toString());
			}
		});
		
				
		Node ruleNode = xmlNode.getLastChild();
		
		 for (Node n2 = ruleNode.getFirstChild(); n2 != null; n2 = n2.getNextSibling()){				
			UiRule treeItem = null;		
			Element rElement = (Element) n2;
			if(rElement.getAttribute("type").equals("Composite")){
				treeItem = new UiRuleComposite();				
				treeItem.generateFromXML(n2);
			}else{
				
				treeItem = new UiDecision();
				treeItem.generateFromXML(n2);
			}
			if(treeItem!=null)
				root.addItem(treeItem);
		}		 
		 ruleCompositionTree.addItem(root);
		 
	}
	
	
	
	

	/**
	 * @return the ruleCompositionTree
	 */
	public Tree getRuleCompositionTree() {
		return ruleCompositionTree;
	}

	/**
	 * @param ruleCompositionTree the ruleCompositionTree to set
	 */
	public void setRuleCompositionTree(Tree ruleCompositionTree) {
		this.ruleCompositionTree = ruleCompositionTree;
	}

	
	/**
	 * @return the listDm
	 */
	public ListBox getListDm() {
		return listDm;
	}

	/**
	 * @param listDm the listDm to set
	 */
	public void setListDm(ListBox listDm) {
		this.listDm = listDm;
	}

	/**
	 * @return the decisionService
	 */
	public DecisionMakerServiceAsync getDecisionService() {
		return decisionService;
	}

	
}
